package com.spzx.gateway.handler;

import org.springframework.cloud.gateway.support.NotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import com.spzx.common.core.utils.ServletUtils;
import reactor.core.publisher.Mono;

/**
 * 网关统一异常处理类，用于捕获和处理网关中的各种异常。
 *
 * @author spzx
 */
@Order(-1) // 设置优先级为最高，确保本异常处理器优先执行
@Configuration // 配置类，定义网关的全局异常处理策略
public class GatewayExceptionHandler implements ErrorWebExceptionHandler
{
    /**
     * 日志对象，用于记录异常信息。
     */
    private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);

    /**
     * 处理服务器web交换中的异常。
     *
     * @param exchange 服务器web交换对象，包含请求和响应
     * @param ex 抛出的异常对象
     * @return Mono<Void> 表示异步处理完成的响应
     */
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
    {
        // 获取响应对象
        ServerHttpResponse response = exchange.getResponse();

        // 如果响应已经提交，则直接返回错误。防止重复响应导致的错误
        if (exchange.getResponse().isCommitted())
        {
            return Mono.error(ex);
        }

        // 初始化异常信息变量
        String msg;

        // 根据异常类型提供不同的错误信息
        if (ex instanceof NotFoundException)
        {
            // 如果是NotFoundException类型的异常，设置消息为"服务未找到"
            msg = "服务未找到";
        }
        else if (ex instanceof ResponseStatusException)
        {
            // 如果是ResponseStatusException类型的异常，获取具体的异常信息
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            msg = responseStatusException.getMessage();
        }
        else
        {
            // 对于其他未知类型的异常，默认返回"内部服务器错误"
            msg = "内部服务器错误";
        }

        // 记录异常日志，包含请求路径和异常信息，便于后续排查问题
        log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());

        // 使用Servlet工具类返回统一的响应，将错误信息写入响应体中
        return ServletUtils.webFluxResponseWriter(response, msg);
    }
}
